#include <iostream>
#include <memory>
#include <vector>
#include <functional>
#include <unistd.h>
#include <unordered_map>

using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;
class timeTask
{
private:
    uint64_t _id;            /*定时器任务id*/
    uint32_t _timeout;       /*定时器的超时时间*/
    bool _cancel;            /*任务是否被取消*/
    TaskFunc _task_fc;       /*定时器要执行的定时任务*/
    ReleaseFunc _release_fc; /*用于删除TimeWheel中保存的定时器对象信息*/
public:
    timeTask(uint64_t id, uint32_t timeout, TaskFunc func)
        : _id(id),
          _timeout(timeout),
          _task_fc(func),
          _cancel(false)

    {
    }

    void Setrealease(const ReleaseFunc &cb)
    {
        _release_fc = cb;
    }

    void Cancel()
    {
        _cancel = true;
    }

    uint32_t GetDelay()
    {
        return _timeout;
    }

    ~timeTask()
    {
        if (_cancel == false) _task_fc();
        _release_fc();
    }
};

class TimeWheel
{
private:
    using Wptr = std::weak_ptr<timeTask>;
    using Sptr = std::shared_ptr<timeTask>;
    int _tick;                                  /*表针*/
    int _capacity;                              /*表盘最大容量*/
    std::vector<std::vector<Sptr>> _wheel;      /*表盘*/
    std::unordered_map<uint64_t, Wptr> _timers; /*表盘中已经保存的定时器*/

private:
    void timerRemove(uint64_t id) /*这个就是移除Timewheel里面保存的定时器的信息*/
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return;
        }
        _timers.erase(it);
    }

public:
    TimeWheel(int capacity = 60, int tick = 0)
        : _capacity(capacity),
          _tick(tick),
          _wheel(_capacity)
    {
    }
    void Timeadd(uint64_t id, uint32_t timeout, TaskFunc func)
    {
        Sptr pt(new timeTask(id, timeout, func));
        pt->Setrealease(std::bind(&TimeWheel::timerRemove, this, id)); /*创建好了定时器*/
        /*将定时器的信息保存下来*/
        _timers[id] = Wptr(pt); /*注意保存的时候要用weakptr， 因为shared_ptr会增加引用计数*/
        /*保存好信息后，也要注意将任务添加到时间轮中去执行*/
        int pos = (timeout + _tick) % _capacity;
        _wheel[pos].push_back(pt); /*tick就是当前的秒针， timeout就是下一次要执行的位置， 代表要在timout秒后进行执行*/
    }

    void TimeCancel(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return;
        }
        Sptr pt = _timers[id].lock();  
        pt->Cancel();
    }
    void Timefresh(uint64_t id)
    {
        /*刷新， 就是在时间轮中添加新的定时任务*/
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return;
        }
        
        // 走到这里， 代表拿到了一个定时器的信息
        /*想要直到这个定时器下次任务的时间， 就得拿到这个定时器的超时时间， 然后让秒针 + 超时时间*/
        Sptr pt = _timers[id].lock();                   /* 将weakptr转化为shared_ptr */
        int pos = (_tick + pt->GetDelay()) % _capacity; /*有可能超过_capacity， 所以要对_capacity进行取模*/
        _wheel[pos].push_back(pt);                      /*利用pt进行拷贝构造， 可以增加引用计数。 然后当退出函数， 在这个函数内部添加的Sptr指针就没了，
                           引用计数只有_wheel里面的。*/
    }

    void OneStep() /*秒针每次移动一步， 然后执行任务， 干掉对应的任务*/
    {
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear();     /*清空指定位置的数组， 就会把数组中保存的所有管理定时器对象的shared_ptr释放掉*/
    }
};


class Test
{
public:
    Test()
    {
        std::cout << "构造" << std::endl;
    }
    ~Test()
    {
        std::cout << "析构" << std::endl;
    }
};

void DeleTest(Test* t)
{
    delete t;
}

int main()
{
    TimeWheel tw;  /*实践轮*/
    
    Test* t = new Test();

    tw.Timeadd(888, 5, std::bind(DeleTest, t));

    int cnt = 1;
    for (int i = 0; i < 5; i++)
    {
        sleep(1);
        tw.Timefresh(888);
        tw.OneStep();     /*刷新888计时器， 同时实践轮向后走一步*/
        std::cout << cnt++ << " " << "刷新了一下定时任务， 需要重新5s后才能销毁" << std::endl;
    }
    tw.TimeCancel(888);
    while (1)
    {
        sleep(1);   
        std::cout << "--------------" << cnt++ << std::endl;
        tw.OneStep();
    }

    return 0;
}   